//
//  TetrisData.cpp
//  app-ios gl
//
//  Created by MeherTj on 2022/1/20.
//  Copyright © 2022 lover. All rights reserved.
//

#include "TetrisData.hpp"

//struct TetrisInfo {
//	std::vector<Pos> items;
//};
Tetris::Tetris()
{
	m_config = std::make_shared<TetrisConfig>();

}
bool Tetris::_is_in_map(std::vector<Pos> const & subs)
{
	for(auto & p : subs)
	{
		if(p.y < 0 || p.x < 0 || p.x >= GMapWidth) return false;
	}
	return true;
}

bool Tetris::_is_in_free_space(const std::vector<Pos> & subs)
{
	for(auto & p : subs)
	{
		if(m_map.get_value_at(p.x, p.y) != 0) return false;
	}
	return true;
}
void Tetris::gen_tetris()
{
	m_current = m_next;
	m_next = m_config->getNext();
}

void Tetris::reset_current_pos()
{
	m_current_pos = { GMapWidth / 2, GMapHeight + 1 };
}
bool Tetris::try_down() {
	return _try_move(0, -1);
}

bool Tetris::try_right() {
	return _try_move(1, 0);
}

bool Tetris::try_left() {
	return _try_move(-1, 0);
}

bool Tetris::try_rotate()
{
	static const int shift_count = 3;
//	return _try_move(0, 0, true);
	auto m = TetrisConfig::GetDirectCount(m_current.type);
	if(m == 1) return false;
	auto direct = (m_current.direct + 1) % m;

	Pos p = m_current_pos;
	for(int i = 0; i < shift_count; ++i) {

		auto poses = TetrisConfig::GetSubPoses(m_current.type, direct, p);
		if(!_is_in_map(poses))
		{
			if(p.x < 2) { ++p.x; continue ;}
			else if(p.x > GMapWidth - 3) { --p.x; continue; }
			else return false;
		}
		if(_is_in_free_space(poses)) {
			m_current_pos = p;
			m_current.direct = direct;
			return true;
		}
	}
	return false;
}

int Tetris::try_quick_down() {
	int t = 0;
	while(try_down()) ++t;
	return t;
}

bool Tetris::put_in()
{
	auto poses = TetrisConfig::GetSubPoses(m_current.type, m_current.direct, m_current_pos);

	bool res = true;
	for(auto & p : poses)
	{
		if(p.x < 0 || p.x >= GMapWidth || p.y < 0 || p.y >= GMapHeight)
		{
			res = false;
		}
		if(m_map.get_value_at(p.x, p.y)) res = false;
		m_map.set(p.x, p.y, m_current.color);
	}
	return res;
}

bool Tetris::_try_move(int x, int y, bool rot) {
	Pos pos;
	pos.x = m_current_pos.x + x;
	pos.y = m_current_pos.y + y;
	auto direct = m_current.direct; //+ (rot?1:0))%TetrisConfig::GetDirectCount(m_current.type);
	auto subs = TetrisConfig::GetSubPoses(m_current.type, direct, pos);
	if(!_is_in_map(subs) || !_is_in_free_space(subs)) return false;

	m_current_pos = pos;
	if(rot) m_current.direct = direct;
	return true;
}
void Tetris::check_result()
{
	std::vector<int> r;
	for(int i = 0; i < GMapHeight; ++i) {
		bool ok = true;
		for(int x = 0; x < GMapWidth; ++x) {
			if(m_map.get_value_at(x, i) == 0) {
				ok = false;
				break;
			}
		}
		if(ok) r.push_back(i);
	}
	m_result.cleared_lines = r;
}
void Tetris::checkout()
{
	auto & r = m_result.cleared_lines;
	// remove the lines
	if(r.size()) {
		int index = 0;
		int tar = r.at(index);
		int src = tar;

		do {
			++src; // the line m was removed, so jump it.
			++index;
			int m = (index >= r.size()? GMapHeight : r.at(index));

			for(; src < m; ++src, ++tar)
			{
				m_map.copy_line(tar, src);
			}
		} while(src < GMapHeight);

		for(; tar < GMapHeight; ++tar) {
			m_map.reset_line(tar, 0);
		}
	}

	m_total_score += r.size();
}

void Tetris::reset()
{
	m_map.reset();
	this->gen_tetris();
	this->gen_tetris();
	m_total_score = 0;
}
